﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using EpidemicSimulator.reports;

namespace EpidemicSimulator
{
    public class SimulationManager
    {
        private Simulation[] simulations;
        private List<SimulationReport> simulationReports;

        public SimulationManager(SimulationSetup simSetup, int numOfExperiments, String pathToSaveDLL)
        {
            simulations = new Simulation[numOfExperiments];
            simulationReports = new List<SimulationReport>();

            for (int i = 0; i < numOfExperiments; i++)
            {
                simulations[i] = SimulationFactory.createSimulation(simSetup, pathToSaveDLL);
                simulations[i].setSimulationStopCallback(simulationStopCallback);
            }
        }

        public void runSimulationAsync()
        {
            foreach (Simulation simulation in simulations)
            {
                ParameterizedThreadStart operation = new ParameterizedThreadStart(Simulation.runSimulation);
                Thread thread = new Thread(operation);
                thread.Start(simulation);
            }
        }

        public void simulationStopCallback(SimulationReport report)
        {
            simulationReports.Add(report);
        }

        public ExperimentState[] getExperimentState()
        {
            ExperimentState[] exStates = new ExperimentState[simulations.Length];
            for (int i = 0; i < exStates.Length; i++)
            {
                lock (simulations[i])
                {
                    exStates[i] = new ExperimentState(simulations[i].simulationRunning, simulations[i].simTime);
                }
            }
            
            return exStates;
        }

        public SimulationSimpleReport getSimulationReport()
        {
            bool allStopped = true;
            foreach (Simulation s in simulations)
            {
                lock (s)
                {
                    if (s.simulationRunning) allStopped = false;
                }
            }

            if (allStopped)
            {
                SimulationSimpleReport report = new SimulationSimpleReport();

                SimulationReport[] reports = new SimulationReport[simulations.Length];
                for(int i=0; i<simulations.Length; i++)
                {
                    reports[i] = simulations[i].getSimulationReport();
                    report.simTime += simulations[i].simTime;
                }
                report.simTime /= simulations.Length;

                SimulationSimpleReportDataSet[] dataSets = new SimulationSimpleReportDataSet[reports[0].dataSets.Length];
                for (int i = 0; i < dataSets.Length; i++)
                {
                    dataSets[i] = new SimulationSimpleReportDataSet();
                    dataSets[i].color = reports[0].dataSets[i].color;
                    dataSets[i].label = reports[0].dataSets[i].label;

                    for (int j = 0; j < reports.Length; j++)
                    {
                        dataSets[i].value += reports[j].dataSets[i].values.Last();
                    }
                    dataSets[i].value /= reports.Length;
                }

                report.dataSets = dataSets;
                return report;
            }

            return null;
        }
    }
}
